/**
 * 定义一个函数类型别名 Fn
 * @template Args - 函数参数的类型，是一个未知类型的数组
 * @template Return - 函数返回值的类型
 */
type Fn<Args extends unknown[], Return> = (...args: Args) => Return;

/**
 * 创建一个防抖函数
 * @template Args - 传入函数的参数类型，是一个未知类型的数组
 * @template Return - 传入函数的返回值类型
 * @template This - 函数调用时的 this 上下文类型，默认为 undefined
 * @param {Fn<Args, Return>} fn - 需要进行防抖处理的函数
 * @param {number} delay - 防抖的延迟时间，单位为毫秒
 * @returns {(this: This, ...args: Args) => void} - 返回一个新防抖函数
 */
export function debounce<
    Args extends unknown[],
    Return,
    This extends Record<string, unknown> | void = void
>(
    fn: Fn<Args, Return>,
    delay: number
): (this: This, ...args: Args) => void {
    // 用于存储 setTimeout 返回的计时器 ID
    let timer: ReturnType<typeof setTimeout> | null = null;

    // 返回一个新的函数，它接收和原函数相同的参数和 this 上下文
    return function (this: This, ...args: Args) {
        // 如果之前已经设置了计时器，清除它，避免多次执行
        if (timer) {
            clearTimeout(timer);
        }

        // 设置一个新的计时器，当延迟时间到达后，执行原函数
        timer = setTimeout(() => {
            // 使用 apply 方法调用原函数，并传入正确的 this 上下文和参数
            fn.apply(this, args);
        }, delay);
    };
}